package main

import (
	"fmt"
	"runtime"
	"time"
)

// 故意制造泄漏：main 结束后子 goroutine 永远阻塞
func leak() {
	ch := make(chan int)
	go func() {
		val := <-ch // 没人再写，永远等
		fmt.Println(val)
	}()
}

func main() {
	fmt.Printf("NumGoroutine before leak: %d\n", runtime.NumGoroutine())
	leak()
	time.Sleep(100 * time.Millisecond)
	fmt.Printf("NumGoroutine after  leak: %d\n", runtime.NumGoroutine())
	// 输出 >1 即证明泄漏
}

// 这个 demo 只是“演示阶段”泄漏，进程退出后 OS 会回收，不算真正的长期泄漏。
// 但它确实能 现场证明“goroutine 数量永久上涨”，满足教学目的；
// 生产环境的泄漏是 进程不退出、goroutine 堆积、内存暴涨

// goroutine 泄漏指的是某些启动的 goroutine 永远阻塞，无法退出，从而浪费内存和调度资源。
// 常见的泄漏场景包括：
// 1. 从未关闭的 channel 读取数据，且没有写入者。
// 2. 在 select 语句中等待多个 channel 操作，但某些 channel 永远不会有数据到来。
// 3. 使用 sync.WaitGroup 等待一组 goroutine 完成，但某些 goroutine 永远不会调用 Done() 方法。
// 为了避免 goroutine 泄漏，建议遵循以下最佳实践：
// 1. 确保所有 channel 都有对应的写入者和读取者，并在不再需要时关闭 channel。
// 2. 在 select 语句中使用 default 分支或超时机制，防止永远阻塞。
// 3. 使用上下文（context）来管理 goroutine 的生命周期，确保它们在不需要时能够退出。
